package com.processmining.controller;

import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpSession;

import org.deckfour.xes.model.XLog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.processmining.entity.Algo;
import com.processmining.entity.EventLog;
import com.processmining.entity.User;
import com.processmining.service.IAlgoService;
import com.processmining.service.IEventLogService;
import com.processmining.service.IMiningService;
import com.processmining.support.C_netFormatter.format.Formatter;
import com.processmining.support.C_netFormatter.format.PetriNet;
import com.processmining.support.C_netFormatter.format.ResourceRelation;
import com.processmining.support.C_netFormatter.format.Sankey;
import com.processmining.support.C_netFormatter.format.TransitionSystem;
import com.processmining.support.analyseSupport.activity.impl.ActivityImpl;
import com.processmining.support.eventLogParse.EventLogParse;
import com.processmining.support.eventLogParse.impl.EventLogParseImpl;
import com.processmining.support.mining.entity.NetElement;
import com.processmining.util.Config;
import com.processmining.util.MiningResult;
import com.processmining.util.request.AlgoParam;
import com.processmining.util.request.ImageType;
import com.processmining.util.request.MiningData;
import com.processmining.util.response.Code;
import com.processmining.util.response.ResponseData;
import com.processmining.util.response.ResponseWithConfig;
import com.processmining.util.response.ResponseWithList;
import com.processmining.util.response.ResponseWithPayload;

import net.ProcessMining.models.heuristics.HeuristicsNet;
import net.ProcessMining.models.heuristics.impl.HNSubSet;

/**
 * 流程挖掘控制器
 * @author hxh12
 *
 */
@Controller
@RequestMapping(value="/logMining")
public class MiningController {
	
	
	@Autowired
	private IAlgoService algoService;
	
	@Autowired
	private IEventLogService eventlogService;
	
	@Autowired
	private IMiningService miningService;
	
	
	// 工作流网
	public final Integer PetriNet = 1;
	
	// 流程图
	public static final Integer TransitionSystem = 2;
	
	// 桑基图
	public static final Integer Sankey = 3;
	
	// 力导向图
	public static final Integer ResourceRelation = 4;
	

	
	@ResponseBody
	@RequestMapping(value="/method",method=RequestMethod.GET)
	public ResponseWithList<Algo> getMiningMethod(){
		ResponseWithList<Algo> response = new ResponseWithList<>();
		response.setCode(Code.SUCCEED);
		response.setData(algoService.listMiningAlgo());
		return response;
		
	}
	
	@ResponseBody
	@RequestMapping(value="/mining",method=RequestMethod.POST)
	public ResponseWithPayload mining(
			@RequestBody MiningData miningdata,
			HttpSession session
								) throws Exception{


		User u = (User)session.getAttribute("user");
		Integer uid = u.getId();
		
		// 从hdfs下载事件日志
		Integer eventLogId =  miningdata.getLogId();
		EventLog log = (EventLog) eventlogService.selectByPK(eventLogId);
		if(log==null){
			throw new FileNotFoundException();
		}
		if(!log.getIsshared()&&log.getCreatorid()!=uid){

			throw new FileNotFoundException();
		}
		
		
		InputStream input = eventlogService.downloadLog(eventLogId);
		
		// 事件日志转换为XLOG
		EventLogParse parser = new EventLogParseImpl();
		XLog xlog = parser.eventLogParse(input);
		input.close();
		
		
		// 获取算法实体
		Algo algo = algoService.getAlgoById(miningdata.getMethodId());
		
		// 算法参数
		HashMap<String,Object> map = new HashMap<String,Object>();
	
		for(AlgoParam param : miningdata.getParamList()){
			//System.out.println(param.getName() + " : " + param.getValue());
			switch (param.getType()) {
			case 1:
				map.put(param.getName(), Integer.valueOf(param.getValue()));
				break;
				
			case 2:
				map.put(param.getName(), Double.valueOf(param.getValue()));
				break;
				
			case 3:
				map.put(param.getName(), Boolean.valueOf(param.getValue()));
				break;

			}
		}
		
		
		// 挖掘
		MiningResult ret = miningService.logMine(miningdata, xlog, algo, map);
		HeuristicsNet net = ret.getNet();
		String usedTime = ret.getUsedTime();
		List<String> traces = ret.getTraces();
		List<String> allTraces = ret.getAllTraces();
        Formatter formatter = null;
        
        
        // 生成对应的图
        switch(miningdata.getImageType()){
        	case ImageType.PetriNet:
        		formatter = new PetriNet(net,usedTime);
        		break;
        		
        	case ImageType.TransitionSystem:
        		formatter = new TransitionSystem(net, usedTime, traces, allTraces);
        		break;
        	
        	case ImageType.Sankey:
        		formatter = new Sankey(net,usedTime);
        		break;

           	case ImageType.ResourceRelation:
           		// TO FIX
                // 力导向图 属性
                ActivityImpl impl=new ActivityImpl();
                Set<String> set = impl.getEventAttrs(xlog);
                Iterator<String> iter = set.iterator();
                String attr = null;
                List<String> RRAttrList = new ArrayList<String>();
                while(iter.hasNext()){
                	RRAttrList.add(iter.next());
                }
           		System.out.println(miningdata.getRrAttr());
                if(miningdata.getRrAttr()!=null&&miningdata.getRrAttr().length()>0)
                	attr = miningdata.getRrAttr();
                else
                	attr = RRAttrList.get(0);
                
           		System.out.println(attr);
        	    formatter = new ResourceRelation(net,usedTime,attr,xlog,2,RRAttrList);
        	    break;
        }

		//loader.close();
		ResponseWithPayload response = new ResponseWithPayload(Code.SUCCEED, formatter);
		return response;
		
	}

	public static List<NetElement> transform(HeuristicsNet net,String time){
		
		List<NetElement> netElementList = new ArrayList<NetElement>();
		Map<Integer,String> names = new HashMap<Integer,String>();
		int size = net.size();
		for(int i=0;i<size;i++){
			names.put(i, net.getActivitiesMappingStructures().getXEventClasses().getByIndex(i).toString());
		}
		HNSubSet starts = net.getStartActivities();
		int start = starts.get(0);
		HNSubSet ends = net.getEndActivities();
		int end = ends.get(0);
		
		int startCount = 0;
		int endCount = 0;
		
		for(int i=0;i<size;i++){
			
			String name = names.get(i);
			NetElement netElement = new NetElement();
			int inputSetSize = net.getInputSet(i).size();
			int outputSetSize = net.getOutputSet(i).size();
			List<String> outputs = new ArrayList<String>();
			List<Integer> subnetlist = new ArrayList<Integer>();
			for(int j=0;j<outputSetSize;j++){
				int subSetSize = net.getOutputSet(i).get(j).size();
				subnetlist.add(subSetSize);
				for(int k=0;k<subSetSize;k++){
					outputs.add(names.get(net.getOutputSet(i).get(j).get(k)));					
				}				
			}
			
			netElement.setElement(Integer.toString(i));
			netElement.setName(name);
			netElement.setOutput(outputs);
			netElement.setSubnetNum(outputSetSize);
			netElement.setSubnetList(subnetlist);
			netElement.setTime(time);
			netElementList.add(netElement);
			
			if(starts.contains(i)){
				System.out.println("startIndex:" + i);
				System.out.println("start:" + name);
			}
			if(ends.contains(i)){
				System.out.println("end:" + name);
			}
			
			if(inputSetSize==0){
				netElement.setIsStart("true");
				startCount++;
			}
			else{
				netElement.setIsStart("false");
			}
			
			if(outputs.size()>0){
				netElement.setIsEnd("false");
			}
			else{
				netElement.setIsEnd("true");
				endCount++;
			}
			
		}
		
		if(startCount == 0){
			for(int i=0;i<starts.size();i++){
				netElementList.get(starts.get(i)).setIsStart("true");
			}
		}
		if(endCount == 0){
			for(int i=0;i<ends.size();i++){
				netElementList.get(ends.get(i)).setIsEnd("true");
			}
		}
		
		
		int currentStart = 0;
		int currentEnd = size-1;
		for(int i=0;i<size;i++){
			
			if(netElementList.get(i).getElement().equals(Integer.toString(start)))
				currentStart = i;
			if(netElementList.get(i).getElement().equals(Integer.toString(end)))
				currentEnd = i;
			
		}
		
		if(currentStart != 0)			
			Collections.swap(netElementList,0,currentStart);
		if(currentEnd != size-1)			
			Collections.swap(netElementList,size-1,currentEnd);			
		
		return netElementList;
		
	}
	
	
	@ResponseBody
	@RequestMapping(value="/algoConfig/{AlgoId}",method=RequestMethod.GET)
	public ResponseData getAlgoParamList(@PathVariable(value="AlgoId")Integer algoId){
		
		ResponseWithConfig response = new ResponseWithConfig();
		
		Config config = algoService.getAlgoConfig(algoId);
		response.setConfig(config);
		response.setCode(Code.SUCCEED);
		return response;
		
	}
	
}
